#include "pattern.h"

#include <QString>
#include <QStringList>
#include <QFile>
#include <QTextStream>
#include "free-cube/datamidi.h"
#include "free-cube/fcexception.h"
#include "free-cube/time.h"
#include "free-cube/logger.h"

using namespace fc;
Pattern::Pattern() :
    n_mesures_(0),
    duration_of_measure_(fc::k_dur_sixteenth),
    n_of_tracks_(0),
    is_loaded_(false)
{
}

Pattern::~Pattern() {
    qDeleteAll (track_);
}
/*
//  file format - space delimeted integers
//  n_mesures_(NM) duration_of_measure_ n_of_tracks_(NT)
//  note-0 note-1 .. note-NT
//  velocity0-0 velocity1-0 .. velocityNT-0
//  velocity0-1 velocity1-1 .. velocityNT-1
//  ...
//  velocity0-NM velocity1-NM .. velocityNT-NM
*/
bool Pattern::load(const QString & name_of_file_){
    if (is_loaded_){ clear(); }
    QStringList string_list;
    QFile text_file(name_of_file_);
    if (!text_file.open(QIODevice::ReadOnly | QIODevice::Text))
        throw FCException("pattern: cant open file " + name_of_file_);

    QTextStream text_stream(&text_file);
    while (true) {
        QString line = text_stream.readLine();
        if (line.isNull()) break;
        else string_list.append(line);
    }

    QStringList header = string_list[0].split( " ", QString::SkipEmptyParts );
    if ( header.length() != 3 ) throw FCException("wrong header length (!=3)");;
    n_mesures_ = header.at(0).toInt();
    duration_of_measure_ = header.at(1).toInt();
    n_of_tracks_ = header.at(2).toInt();

    if(n_of_tracks_ <= 0) throw FCException("wrong number of tracks (<=0)");
    QStringList notes = string_list[1].split(" ", QString::SkipEmptyParts);

    for ( int i = 0; i < n_of_tracks_; ++i )
        notes_.append(notes.at(i).toInt());

    for ( int j = 0; j < n_mesures_; ++j ) {
        Mesure * m = new Mesure;
        QStringList velocities = string_list[j+1].
                split(" ", QString::SkipEmptyParts);
        for (int i = 0; i < n_of_tracks_; ++i){
            m->append(velocities.at(i).toInt());
        }
        track_.append(m);
    }
    is_loaded_ = true;
    ticks_per_mesure_ = int (
            k_ticks_in_16th * float(fc::k_dur_sixteenth) /
            float(duration_of_measure_));
    return true;
}

void Pattern::clear(){
    if ( is_loaded_ ){
        qDeleteAll (track_);
        is_loaded_ = false;
    }
};

void Pattern::get_data(fc::DataList & data, fc::TimeT ticks_from,
                       fc::TimeT ticks_to)
{
    //fc::log("Pattern data : %1 , %2", ticks_from , ticks_to);
    int mesure_from = float(ticks_from)/ ticks_per_mesure_;
    int mesure_to = float(ticks_to) / ticks_per_mesure_;
    if (mesure_from >= n_mesures_ || mesure_from < 0 ||
            mesure_from >= mesure_to) return;
    if (mesure_to > n_mesures_) mesure_to = n_mesures_;

    for (int mesure_n = mesure_from; mesure_n < mesure_to; ++mesure_n){
        Mesure * mesure = track_[mesure_n];
                for (int track_n = 0; track_n < n_of_tracks_; ++track_n){
                    int velocity = mesure->at(track_n);
            if ( velocity > 0)
                data.append(
                            new fc::DataMidi(
                                fc::smf::k_note_on,
                                notes_[track_n],
                                velocity,
                                mesure_n * ticks_per_mesure_));
            }
    }
}
